package com.guorou.htmllatex.util;

import com.guorou.htmllatex.latex.LaTeXRenderPolicy;
import com.guorou.htmllatex.math.MathMLUtils;
import fmath.conversion.ConvertFromLatexToMathML;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Triple;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;
import uk.ac.ed.ph.snuggletex.SnuggleEngine;
import uk.ac.ed.ph.snuggletex.SnuggleInput;
import uk.ac.ed.ph.snuggletex.SnuggleSession;
import uk.ac.ed.ph.snuggletex.definitions.CorePackageDefinitions;
import uk.ac.ed.ph.snuggletex.internal.util.XMLUtilities;
import uk.ac.ed.ph.snuggletex.utilities.DefaultTransformerFactoryChooser;

import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class LatexUtils {
    private static ThreadLocal<SnuggleSession> snuggleSessionThreadLocal = new ThreadLocal<>();

    public static String LatexToMathML(String latex) {
        if(StringUtils.isNotEmpty(latex)) {
            if (validate(latex)) {
                SnuggleSession session = snuggleSessionThreadLocal.get();
                NodeList nodeList = session.buildDOMSubtree();
                int length = nodeList.getLength();
                for (int i = 0; i < length; i++) {
                    Node node = nodeList.item(i);
                    if (node instanceof Text) {
                    } else if ("math".equals(node.getLocalName())) {
                        String math = XMLUtilities.serializeNode(node,
                                Initializer.SNUGGLE_ENGINE.getDefaultXMLStringOutputOptions());
                        return math;
                    }
                }
            }
//            return LatexPostHandle(ConvertFromLatexToMathML.convertToMathML(latex));
        }
        return "";
    }

    private static boolean validate(String data) {
        SnuggleSession session = snuggleSessionThreadLocal.get();
        if (StringUtils.isBlank(data)) {
            return false;
        }

        // https://www2.ph.ed.ac.uk/snuggletex/documentation/overview-and-features.html
        session = Initializer.SNUGGLE_ENGINE.createSession();
        SnuggleInput input = new SnuggleInput(data);
        boolean valid = false;
        try {
            valid = session.parseInput(input);
        } catch (IOException ignored) {
            // Will never throw an exception since input is raw string
        }
        snuggleSessionThreadLocal.set(session);
        return valid;
    }

    public static String LatexPostHandle(String mathml){
        mathml = mathml.replace("&nbsp;","");
        mathml = mathml.replaceFirst("<math mathvariant='italic'>","<math xmlns=\"http://www.w3.org/1998/Math/MathML\">");
        return mathml;
    }

    public static String HtmlLatexConvert(String latexHtml){
        LinkedHashMap<String,String> latexMap = new LinkedHashMap();
        int handleIndex = latexMap.size();
        String regex = "\\$\\$(.*?)\\$\\$";
        Pattern p = Pattern.compile(regex);
        Matcher m = p.matcher(latexHtml);
        StringBuffer stringBuffer = new StringBuffer();
        int matcher_start = 0;
        while(m.find(matcher_start)){
            String genText = latexHtml.substring(matcher_start,m.start());
            if(StringUtils.isNotEmpty(genText)){
                stringBuffer.append(genText);
            }
            String latexText = latexHtml.substring(m.start(),m.end());
            if(StringUtils.isNotEmpty(latexText)){
                String latexPlaceholder = String.format("{{latex%s}}",handleIndex++);
                stringBuffer.append(latexPlaceholder);
                latexMap.put(latexPlaceholder,LatexToMathML(latexText));
            }
            matcher_start = m.end();
        }
        if(matcher_start < latexHtml.length()){
            stringBuffer.append(latexHtml.substring(matcher_start,latexHtml.length()));
        }
        latexHtml = stringBuffer.toString();
        if(latexMap.size() > 0){
            for(Map.Entry<String,String> element : latexMap.entrySet()) {
                latexHtml = latexHtml.replace(element.getKey(), element.getValue());
            }
        }
        return latexHtml;
    }

    private static class Initializer {
        static final SnuggleEngine SNUGGLE_ENGINE = new SnuggleEngine(DefaultTransformerFactoryChooser.getInstance(), null);

        static {
            CorePackageDefinitions.getPackage().loadMathCharacterAliases("math-character-aliases.txt");
        }
    }

}
